home *** CD-ROM | disk | FTP | other *** search
- /*
- * Display.c - Darstellung der C64-Grafik,
- * Handhabung des Emulatorfensters
- *
- * Copyright (C) 1994-1995 by Christian Bauer
- */
-
- /*
- * Anmerkungen:
- * ------------
- *
- * - Die Farbpalette besteht aus den 16 C64-Farben, 16mal wiederholt.
- * Dadurch spart man sich das Ausmaskieren der unteren 4 Bit bei den
- * VIC-Farbcodes. Allerdings muß dieses bei der Chunky->Planar-
- * Konvertierung für die Amiga-Chips erfolgen (der Algorithmus
- * setzt voraus, daß die oberen Nibbles Null sind).
- */
-
- #include <exec/types.h>
- #include <exec/libraries.h>
- #include <exec/memory.h>
- #include <intuition/intuition.h>
- #include <intuition/screens.h>
- #include <libraries/gadtools.h>
- #include <devices/timer.h>
- #include <clib/exec_protos.h>
- #include <clib/intuition_protos.h>
- #include <clib/graphics_protos.h>
- #include <clib/gadtools_protos.h>
- #include <clib/timer_protos.h>
- #include <string.h>
-
- #include "Display.h"
- #include "SAM.h"
- #include "Prefs.h"
- #define CATCOMP_NUMBERS 1
- #include "LocStrings.h"
-
-
- // Aus Main.asm
- extern struct Library *GfxBase;
- extern struct Library *IntuitionBase;
- extern void ShowPrefs(void);
- extern void PutChProc(void);
- extern char *GetStr(int strnum);
-
- // Aus 6510.asm
- extern struct Task *CPUTask;
- extern void Pause6510(void);
- extern void Resume6510(void);
-
- // Aus 6526.asm
- extern void KeyPressed(char c);
-
- // Aus 6569.asm
- extern APTR CURRENTA5;
- extern BYTE ChunkyBuf[];
- extern UWORD SkipLatch;
- extern UWORD LimitSpeed;
-
- // Aus 6581.asm
- extern void PauseSound(void);
- extern void ResumeSound(void);
-
- // Aus c2p4.asm
- extern void c2p4(UBYTE *fBUFFER, UBYTE *fBUFFER_CMP, APTR *planes, struct Task *task, ULONG signals);
- extern int Initc2p4(void);
- extern void Exitc2p4(void);
-
-
- // Prototypes
- void open_double_buf(int type, int width, int height);
- int handle_IDCMP(int done);
- int handle_menu(int menu, int item, int done);
-
-
- char has_gfx_39, has_gfx_40; // Flags für Version der graphics.library
-
- int current_type, current_width, current_height;
-
- struct Screen *the_screen;
- struct Window *the_window;
- struct VisualInfo *the_visual_info;
- struct RastPort *the_rast_port;
- struct ViewPort *the_view_port;
- struct TextFont *topaz_font;
- struct Menu *the_menus;
-
- // Für WritePixelArray8()
- struct BitMap *temp_bm;
- struct BitMap v37_temp_bm;
- struct RastPort temp_rp;
-
- // Double Buffering
- struct ScreenBuffer *scr_buf[2];
- int inv_buf_num;
- char using_db; // Flag: Double Buffering wird benutzt
-
- // c2p4
- APTR comparison_buf[2];
- char c2p4_signal; // Signal: c2p4 fertig
- LONGBITS c2p4_set;
- char must_wait_for_c2p4; // Flag: Auf c2p4 muß gewartet werden
-
- // Geschwindigkeitsanzeige
- struct MsgPort *timer_port;
- struct timerequest *timer_io;
-
-
- const struct TextAttr topaz_attr = {
- "topaz.font", 8, FS_NORMAL, 0
- };
-
- struct NewMenu new_menus[] = {
- NM_TITLE, MSG_EMULATION_MENU, NULL, 0, 0, NULL,
- NM_ITEM, MSG_SETTINGS_MENU, NULL, 0, 0, NULL,
- NM_ITEM, MSG_SAM_MENU, "M", 0, 0, NULL,
- NM_ITEM, NM_BARLABEL, NULL, 0, 0, NULL,
- NM_ITEM, MSG_QUIT_MENU, "Q", 0, 0, NULL,
- NM_END, NULL, NULL, 0, 0, NULL
- };
-
- const UBYTE palette_red[16] = {
- 0, 15, 12, 0, 15, 0, 0, 15, 15, 8, 15, 4, 8, 8, 8, 12
- };
-
- const UBYTE palette_green[16] = {
- 0, 15, 0, 15, 0, 12, 0, 15, 8, 4, 8, 4, 8, 15, 8, 12
- };
-
- const UBYTE palette_blue[16] = {
- 0, 15, 0, 12, 15, 0, 12, 0, 0, 0, 8, 4, 8, 8, 15, 12
- };
-
-
- /*
- * Screen und Fenster öffnen, alles vorbereiten
- * 0: OK, 1: Fehler beim Screen-Öffnen, 2: Kein Speicher
- */
-
- int OpenDisplay(int type, ULONG display_id, UWORD overscan, int width, int height)
- {
- int depth;
- int i;
-
- has_gfx_39 = (GfxBase->lib_Version >= 39);
- has_gfx_40 = (GfxBase->lib_Version >= 40);
-
- must_wait_for_c2p4 = FALSE;
- using_db = FALSE;
-
- current_type = type;
- current_width = width;
- current_height = height;
-
- switch (type) {
- case SCRTYPE_8BIT: depth = 8; break;
- case SCRTYPE_4BIT: depth = 4; break;
- case SCRTYPE_1BIT: depth = 1; break;
- }
-
- if (!(the_screen = OpenScreenTags(NULL,
- SA_Width, width,
- SA_Height, height,
- SA_DisplayID, display_id,
- SA_Overscan, overscan,
- SA_Depth, depth,
- SA_Quiet, TRUE,
- SA_AutoScroll, TRUE,
- TAG_DONE)))
- return 1;
-
- the_rast_port = &the_screen->RastPort;
- the_view_port = &the_screen->ViewPort;
-
- if (topaz_font = OpenFont(&topaz_attr))
- SetFont(the_rast_port, topaz_font);
- SetAPen(the_rast_port, 1);
-
- if (!(the_visual_info = GetVisualInfo(the_screen, NULL)))
- return 2;
-
- if (!(the_menus = CreateMenus(new_menus, GTMN_FullMenu, TRUE, TAG_DONE)))
- return 2;
- LayoutMenus(the_menus, the_visual_info, GTMN_NewLookMenus, TRUE, TAG_DONE);
-
- if (!(the_window = OpenWindowTags(NULL,
- WA_Left, 0,
- WA_Top, 0,
- WA_Width, width,
- WA_Height, height,
- WA_CustomScreen, the_screen,
- WA_IDCMP, IDCMP_RAWKEY | IDCMP_MENUPICK | IDCMP_MENUVERIFY,
- WA_Backdrop, TRUE,
- WA_Borderless, TRUE,
- WA_NoCareRefresh, TRUE,
- WA_Activate, TRUE,
- WA_NewLookMenus, TRUE,
- TAG_DONE)))
- return 2;
-
- SetMenuStrip(the_window, the_menus);
-
- switch (type) {
- case SCRTYPE_8BIT:
-
- // Farbpalette laden
- for (i=0; i<256; i++)
- SetRGB4(the_view_port, i,
- palette_red[i & 0xf], palette_green[i & 0xf], palette_blue[i & 0xf]);
-
- // Temporären RastPort für WritePixelArray8() anlegen
- if (has_gfx_39) {
- if (!(temp_bm = AllocBitMap(width, 1, 8, 0, NULL)))
- return 2;
- } else {
- InitBitMap(temp_bm = &v37_temp_bm, depth, width, 1);
- for (i=0; i<8; i++)
- if (!(v37_temp_bm.Planes[i] = AllocRaster(width, 1)))
- return 2;
- }
-
- InitRastPort(&temp_rp);
- temp_rp.BitMap = temp_bm;
-
- CURRENTA5 = ChunkyBuf; // Wird nicht mehr verändert
- break;
-
- case SCRTYPE_4BIT:
-
- if (!Initc2p4())
- return 2;
-
- // Speicher für Comparison Buffer holen
- if (!(comparison_buf[0] = AllocVec(width * height, MEMF_PUBLIC | MEMF_CLEAR)))
- return 2;
-
- // Farbpalette laden
- for (i=0; i<16; i++)
- SetRGB4(the_view_port, i,
- palette_red[i & 0xf], palette_green[i & 0xf], palette_blue[i & 0xf]);
-
- CURRENTA5 = ChunkyBuf;
-
- open_double_buf(type, width, height);
- must_wait_for_c2p4 = FALSE;
- break;
-
- case SCRTYPE_1BIT:
-
- SetRGB4(the_view_port, 0, 0, 0, 0); // schwarz
- SetRGB4(the_view_port, 1, 15, 15, 15); // weiß
-
- CURRENTA5 = the_rast_port->BitMap->Planes[0];
-
- open_double_buf(type, width, height);
- break;
- }
-
- return 0;
- }
-
-
- /*
- * Double Buffering einrichten
- */
-
- void open_double_buf(int type, int width, int height)
- {
- using_db = FALSE;
- if (IntuitionBase->lib_Version >= 39) {
-
- if (!(scr_buf[0] = AllocScreenBuffer(the_screen, NULL, SB_SCREEN_BITMAP)))
- return;
-
- if (!(scr_buf[1] = AllocScreenBuffer(the_screen, NULL, SB_COPY_BITMAP)))
- return;
-
- WaitTOF(); WaitTOF();
- inv_buf_num = 1;
-
- if (type == SCRTYPE_4BIT) {
- CURRENTA5 = ChunkyBuf;
- if (!(comparison_buf[1] = AllocVec(width * height, MEMF_PUBLIC | MEMF_CLEAR)))
- return;
- } else {
- CURRENTA5 = scr_buf[1]->sb_BitMap->Planes[0];
- }
-
- using_db = TRUE;
- }
- }
-
-
- /*
- * Screen und Fenster schließen
- */
-
- void CloseDisplay(void)
- {
- int i;
-
- if (current_type == SCRTYPE_4BIT)
- Exitc2p4();
-
- if (comparison_buf[0]) {
- FreeVec(comparison_buf[0]);
- comparison_buf[0] = NULL;
- }
-
- if (comparison_buf[1]) {
- FreeVec(comparison_buf[1]);
- comparison_buf[1] = NULL;
- }
-
- FreeScreenBuffer(the_screen, scr_buf[0]); // NULL ist OK
- scr_buf[0] = NULL;
- FreeScreenBuffer(the_screen, scr_buf[1]);
- scr_buf[1] = NULL;
-
- if (the_menus) {
- ClearMenuStrip(the_window);
- FreeMenus(the_menus);
- the_menus = NULL;
- }
-
- if (the_window) {
- CloseWindow(the_window);
- the_window = NULL;
- }
-
- // Temporären RastPort schließen
- if (temp_bm) {
- if (has_gfx_39)
- FreeBitMap(temp_bm);
- else {
- for (i=0; i<8; i++) {
- FreeRaster(v37_temp_bm.Planes[i], current_width, current_height);
- v37_temp_bm.Planes[i] = NULL;
- }
- }
- temp_bm = NULL;
- }
-
- if (the_visual_info) {
- FreeVisualInfo(the_visual_info);
- the_visual_info = NULL;
- }
-
- if (topaz_font) {
- CloseFont(topaz_font);
- topaz_font = NULL;
- }
-
- if (the_screen) {
- CloseScreen(the_screen);
- the_screen = NULL;
- }
- }
-
-
- /*
- * Vom 6510-Task aus nötige Initialisierungen
- * Wird vom 6510-Task aufgerufen
- */
-
- void InitDisplayFrom6510(void)
- {
- // Signal für c2p4
- c2p4_signal = AllocSignal(-1);
- c2p4_set = 1 << c2p4_signal;
-
- // TimerIO einrichten
- if (timer_port = CreateMsgPort()) {
- if (timer_io = CreateIORequest(timer_port, sizeof(struct timerequest))) {
- OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_io, 0);
-
- // timer_io für Speed Limiter starten
- timer_io->tr_node.io_Command = TR_ADDREQUEST;
- timer_io->tr_time.tv_secs = 0;
- timer_io->tr_time.tv_micro = SkipLatch * 20000; // 20ms pro Bild
- SendIO((struct IORequest *)timer_io);
- }
- }
- }
-
-
- /*
- * Vom 6510-Task aus nötige Aufräumarbeiten
- * Wird vom 6510-Task aufgerufen
- */
-
- void ExitDisplayFrom6510(void)
- {
- if (timer_io) {
- if (!CheckIO((struct IORequest *)timer_io))
- WaitIO((struct IORequest *)timer_io);
- CloseDevice((struct IORequest *)timer_io);
- DeleteIORequest((struct IORequest *)timer_io);
- timer_io = NULL;
- }
-
- if (timer_port) {
- DeleteMsgPort(timer_port);
- timer_port = NULL;
- }
-
- // Ggf. auf Signal von c2p4 warten
- if (must_wait_for_c2p4)
- Wait(c2p4_set);
-
- FreeSignal(c2p4_signal);
- }
-
-
- /*
- * C64-Grafik neu darstellen (VBlank, Double Buffering)
- * Wird vom 6510-Task aufgerufen
- */
-
- struct timeval start_time, end_time;
- char speed_str[20];
- int percent;
-
- void RedrawDisplay(void)
- {
- switch (current_type) {
- // SCRTYPE_8BIT: WritePixelLine in 6569.asm
-
- case SCRTYPE_4BIT: // Double Buffering und c2p-Konvertierung
- if (must_wait_for_c2p4)
- Wait(c2p4_set);
-
- if (using_db) {
- while (!ChangeScreenBuffer(the_screen, scr_buf[inv_buf_num]))
- WaitTOF();
- inv_buf_num ^= 1;
- c2p4(ChunkyBuf, comparison_buf[inv_buf_num], scr_buf[inv_buf_num]->sb_BitMap->Planes, CPUTask, c2p4_set);
- } else
- c2p4(ChunkyBuf, comparison_buf[0], the_rast_port->BitMap->Planes, CPUTask, c2p4_set);
-
- must_wait_for_c2p4 = TRUE;
- CURRENTA5 = ChunkyBuf;
- break;
-
- case SCRTYPE_1BIT: // Double Buffering
- if (using_db) {
- while (!ChangeScreenBuffer(the_screen, scr_buf[inv_buf_num]))
- WaitTOF();
- inv_buf_num ^= 1;
- CURRENTA5 = scr_buf[inv_buf_num]->sb_BitMap->Planes[0];
- } else
- CURRENTA5 = the_rast_port->BitMap->Planes[0];
- break;
- }
-
- if (timer_io) {
- // timer_io abbrechen, wenn Speed Limiter aus ist
- if (!LimitSpeed)
- if (!CheckIO((struct IORequest *)timer_io))
- AbortIO((struct IORequest *)timer_io);
-
- WaitIO((struct IORequest *)timer_io);
-
- // timer_io neu starten
- timer_io->tr_node.io_Command = TR_ADDREQUEST;
- timer_io->tr_time.tv_secs = 0;
- timer_io->tr_time.tv_micro = SkipLatch * 20000; // 20ms pro Bild
- SendIO((struct IORequest *)timer_io);
- }
-
- // Zeit seit letztem Aufruf ermitteln
- GetSysTime(&end_time);
- SubTime(&end_time, &start_time);
- GetSysTime(&start_time);
-
- // Ein Bild sollte 20ms dauern
- percent = (20000 * 100 / end_time.tv_micro + 1) * SkipLatch;
-
- RawDoFmt("%ld%%", &percent, &PutChProc, speed_str);
- Move(the_rast_port, 4, current_height-6);
- Text(the_rast_port, speed_str, strlen(speed_str));
- }
-
-
- /*
- * C64-Grafik nach hinten
- */
-
- void EmulToBack(void)
- {
- ScreenToBack(the_screen);
- ModifyIDCMP(the_window, IDCMP_RAWKEY);
- ClearMenuStrip(the_window);
- }
-
-
- /*
- * C64-Grafik nach vorne
- */
-
- void EmulToFront(void)
- {
- ScreenToFront(the_screen);
- ModifyIDCMP(the_window, IDCMP_RAWKEY | IDCMP_MENUPICK | IDCMP_MENUVERIFY);
- SetMenuStrip(the_window, the_menus);
- }
-
-
- /*
- * Event-Schleife des Fensters
- */
-
- void EventLoop(void)
- {
- int done = FALSE;
-
- while (!done) {
- WaitPort(the_window->UserPort);
- done = handle_IDCMP(done);
- }
- }
-
-
- /*
- * IDCMP-Messages handhaben
- */
-
- int handle_IDCMP(int done)
- {
- struct IntuiMessage *msg;
- ULONG class;
- UWORD code;
- UWORD menu_number;
- struct MenuItem *item;
-
- while (!done && (msg = GetMsg(the_window->UserPort))) {
- class = msg->Class;
- code = msg->Code;
-
- if (class == IDCMP_MENUVERIFY)
- Pause6510(); // Subtask stoppen
-
- ReplyMsg((struct Message *)msg);
-
- switch (class) {
- case IDCMP_MENUPICK:
- Resume6510(); // Subtask fortführen
-
- menu_number = code;
- while (!done && (menu_number != MENUNULL)) {
- item = ItemAddress(the_window->MenuStrip, menu_number);
- done = handle_menu(MENUNUM(menu_number), ITEMNUM(menu_number), done);
- menu_number = item->NextSelect;
- }
- break;
-
- case IDCMP_RAWKEY:
- if (code == 0x58) // F9 -> Einstellungen
- handle_menu(0, 0, done);
- else
- KeyPressed(code);
- break;
- }
- }
-
- return done;
- }
-
-
- /*
- * Menü wurde ausgewählt
- */
-
- int handle_menu(int menu, int item, int done)
- {
- if (menu == 0) {
- switch (item) {
- case 0: // Einstellungen
- Pause6510();
- PauseSound();
- EmulToBack();
- ShowPrefs();
- EmulToFront();
- ResumeSound();
- Resume6510();
- break;
-
- case 1: // SAM
- Pause6510();
- PauseSound();
- EmulToBack();
- SAM();
- EmulToFront();
- ResumeSound();
- Resume6510();
- break;
-
- case 3: // Quit
- done = TRUE;
- break;
- }
- }
-
- return done;
- }
-
-
- /*
- * Requester anzeigen
- */
-
- int ShowRequester(int text, int gads, APTR args)
- {
- struct EasyStruct es;
-
- es.es_StructSize = sizeof(struct EasyStruct);
- es.es_Flags = 0;
- es.es_Title = GetStr(MSG_REQTITLE);
- es.es_TextFormat = GetStr(text);
- es.es_GadgetFormat = GetStr(gads);
-
- return EasyRequestArgs(NULL, &es, NULL, args);
- }
-
-
- /*
- * Lokalisierungen vornehmen
- */
-
- void LocalizeDisplay(void)
- {
- int i;
-
- for (i=0; new_menus[i].nm_Type != NM_END; i++)
- if (new_menus[i].nm_Label != NM_BARLABEL)
- new_menus[i].nm_Label = GetStr((int)new_menus[i].nm_Label);
- }
-